<?php

/*
This class has data and functions needed for entity reconciliation
*/

class ReconciliationServices{
    
    public $reconKey; //name or key of the reconciliation service being called
    public $GRprojectID; //google refine project id
    public $baseColumnName; //name of the base column with data to be reconciled
    public $columnInsertIndex; //index for the new column of raw data from reconcilation service to be inserted
    public $FinishColumnInsertIndex; //index for new column of finished URIs
    
    public $pendingProgress; //process on pending processes
    public $pendingProcesses; // array of pending processes
    public $startMessage; //array of parameters to be POSTed to Google Refine to start reconciliation
    public $finishMessage; //array of parameters to be POSTed to Google Refine to process JSON into entity URIs
    public $cleanupMessage; //array of parameters to be POSTed to Google Refine to remove the JSON data from the Google Refine project
    
    public $nextFinishIndex; //if there's a next finish stage (to make multiple columns of results), the index for the next stage is set here
    
    public $fallBack_issueProfile_id; // issue tracker profile ID.
    public $issueUserID; //user id for the final issue created / reported after the reconcilation service
    public $finalReconIssue; //number for the final issue created / reported after the reconcilation service creation of new column(s) is completed
    
    
    public $refineHumanURI; //human readable base URI for google refine
    public $refineURI; //base URI for google refine
    public $getColsURL = "/command/core/get-models"; //url to get columns from the Google Refine project / table
    public $pendingURL = "/command/core/get-processes"; //url for pending processes
    public $startCommandURL = "/command/core/add-column-by-fetching-urls"; //url for start command
    public $finishCommandURL = "/command/core/add-column"; //url for finishing the process, parsing the json to make the URLs
    public $cleanupCommandURL = "/command/core/remove-column"; //url to remove the scratch field
    
    public $cancelCommandURL = "/command/core/cancel-processes"; //url to end the process
    
    const directoryType = "processes"; //location of ongoing processes, stored as JSON files
    
    public $settings = array("EOL" => array ("title" => "Encyclopedia of Life",
                                             "about" => "biological taxa",
                                             "baseURL" => "http://eol.org/",
                                             "docURL" => "http://eol.org/api",
                                             "StartGrel" => "grel: \"http://eol.org/api/search/1.0/\" + escape(value, \"url\") + \".json\" ",
                                             "NewPrefix" => "EOL JSON Data for ",
                                             "Finish" => array( 1 => array("Grel" => "grel: \"http://eol.org/pages/\" + value.parseJson()[\"results\"][0][\"id\"]",
                                                                            "FinishPrefix" => "EOL URIs for "
                                                                           ),
                                                                2 => array("Grel" => "grel: value.parseJson()[\"results\"][0][\"title\"] ",
                                                                            "FinishPrefix" => "EOL title / label for "
                                                                           )
                                                               ),
                                             "delay" => 3500,
                                             "onError" => "set-to-blank"
                                             ),
                             
                             "Pleiades" => array ("title" => "Pleiades",
                                             "about" => "Gazettteer of ancient places of Europe, the Mediterranean, and the Near East",
                                             "baseURL" => "http://pleiades.stoa.org/",
                                             "docURL" => "http://pleiades.stoa.org/",
                                             "StartGrel" => "grel: \"http://bacchus.atlantides.org/r/pleiades/reconcile?type=Place&query=\" + escape(value, \"url\") ",
                                             "NewPrefix" => "Pleiades JSON Data for ",
                                             "Finish" => array( 1 => array("Grel" => "grel: \"http://pleiades.stoa.org/\" + value.parseJson()[\"result\"][0][\"id\"]",
                                                                            "FinishPrefix" => "Pleiades URIs for "
                                                                           ),
                                                                2 => array("Grel" => "grel: value.parseJson()[\"result\"][0][\"name\"]",
                                                                            "FinishPrefix" => "Pleiades name for "
                                                                           )
                                                               ),
                                             "delay" => 3000,
                                             "onError" => "set-to-blank"
                                             ),
                             
                             
                             );



    //returns parameters, needed to finish a process OR false, if no parameters stored
    public function getReconProcess(){
        
        $JSONstore = new JSONstore;
        $JSONstore->setDirectory(self::directoryType);
        $process = $JSONstore->read_parse_json($this->GRprojectID);
        return $process; 
    }

    //saves parameters needed to finish a process OR false, if no parameters stored
    public function cacheReconProcess($message){
        
        $messageJSON = json_encode($message, 1);
        
        $JSONstore = new JSONstore;
        $JSONstore->setDirectory(self::directoryType);
        $JSONstore->save_json($this->GRprojectID, $messageJSON );
    }

    //deletes any stored process parameters
    public function deleteReconProcess(){
        $JSONstore = new JSONstore;
        $JSONstore->setDirectory(self::directoryType);
        $JSONstore->delete_json($this->GRprojectID);
    }


    public function getGRprojectCols(){
        $output = false;
        @$json = file_get_contents($this->refineURI.$this->getColsURL."?project=".$this->GRprojectID);
        if($json != false){
            $meta = json_decode($json, 1);
            $output = $meta["columnModel"]["columns"];
        }
        
        return $output;
    }




    //check to see if there are pending processes, if so, don't try to do reconciliation
    public function checkPending(){
        
        $this->pendingProgress = false;
        $pendingProcesses = false;
        $output = false;
        @$pendingString = file_get_contents($this->refineURI.$this->pendingURL."?project=".$this->GRprojectID);
        if($pendingString ){
           $pending = json_decode($pendingString, 1);
           if(is_array($pending["processes"])){
                if(count($pending["processes"])>0){
                    $output = true;
                    $pendingProcesses = $pending["processes"];
                    $this->pendingProgress = $pendingProcesses[0]["progress"];
                }
           }
        }
        
        $this->pendingProcesses =  $pendingProcesses;
        return $output; //ouput's true if there's a pending process 
    }


    //start the entity reconciliation process (if nothing is pending)
    public function ReconStart(){
        
        $waitForPending = $this->checkPending(); //if true, wait for pending
        if(!$waitForPending){
            $ActSettings = $this->getSettings($this->reconKey);
            if(is_array($ActSettings)){
                $newColumnName = $ActSettings["NewPrefix"].$this->baseColumnName;
                
                //these are post parameters for making a new column based using EOL URIs
                $message = array("baseColumnName" => $this->baseColumnName,
                         "urlExpression" => $ActSettings["StartGrel"],
                         "newColumnName" => $newColumnName,
                         "columnInsertIndex" => $this->columnInsertIndex,
                         "delay" =>  $ActSettings["delay"],
                         "onError" => $ActSettings["onError"],
                         "project" => $this->GRprojectID
                         );
                
                $this->startMessage = $message;
                return $message;
            }
            else{
                return false;
            }
        }
        else{
            return false;
        }
        
    }//end function
    
    
    //finish the entity reconciliation process, if nothing is pending
    public function ReconFinish($finishIndex){
        
        $this->nextFinishIndex = false;
        $waitForPending = $this->checkPending(); //if true, wait for pending
        if(!$waitForPending){
            $ActSettings = $this->getSettings($this->reconKey);
            if(is_array($ActSettings)){
                $StartColumnName = $ActSettings["NewPrefix"].$this->baseColumnName;
                
                if(array_key_exists($finishIndex, $ActSettings["Finish"])){
                    $FinishColumnName = $ActSettings["Finish"][$finishIndex]["FinishPrefix"].$this->baseColumnName;
                    $Grel = $ActSettings["Finish"][$finishIndex]["Grel"];
                    
                    //see if there's another finish column to create, it so put the index number in $this->nextFinishIndex
                    $nextFinishIndex = $finishIndex + 1;
                    if(array_key_exists($nextFinishIndex, $ActSettings["Finish"])){
                        $this->nextFinishIndex = $nextFinishIndex;
                    }
                    
                    //these are post parameters for making a new column based using EOL URIs
                    $message = array(
                             "baseColumnName" => $StartColumnName, //column name with the raw, usually, JSON, data from reconciliation service
                             "expression" => $Grel,
                             "newColumnName" => $FinishColumnName,
                             "columnInsertIndex" => $this->FinishColumnInsertIndex,
                             "onError" => $ActSettings["onError"],
                             "project" => $this->GRprojectID
                             );
                }
                else{
                    $message = false;
                }
                
                $this->finishMessage = $message;
                return $message;
            }
            else{
                return false;
            }
        }
        else{
            return false;
        }
        
    }//end function
    
    
    //clean up the raw data from the reconciliation service
    public function CleanUpRawServiceData(){
        
        $waitForPending = $this->checkPending(); //if true, wait for pending
        if(!$waitForPending){
            $ActSettings = $this->getSettings($this->reconKey);
            if(is_array($ActSettings)){
                $RemoveColumnName = $ActSettings["NewPrefix"].$this->baseColumnName;
                
                //these are post parameters for making a new column based using EOL URIs
                $message = array(
                         "columnName" => $RemoveColumnName,
                         "project" => $this->GRprojectID
                         );
                
                $this->cleanupMessage = $message;
                return $message;
            }
            else{
                return false;
            }
        }
        else{
            return false;
        }
        
    }//end function
    
    
    
    //create a new issue in the issue tracker
    public function createReconcilationIssue($tableMetadata){
        
        $ActSettings = $this->getSettings($this->reconKey);
        
        
        $GRprojectName = $tableMetadata["name"];
        $GRprojectID = $this->GRprojectID;
        
        
        $host = "http://".$_SERVER['SERVER_NAME'];
        $summaryLink = $host."/plugin.php?page=DataRefine/data-doc-summary&grProject=".$GRprojectID;
        
        
        $summary = "Check ".$ActSettings["title"]." Entity Reconcilation Results for '".$this->baseColumnName."' of '".$GRprojectName."' ";
        
        $description = "Please review ".$ActSettings["title"]." entity reconcilation results for the column '".$this->baseColumnName."' ";
        $description .= "of dataset: '$GRprojectName' (original name) at ".$this->refineHumanURI."/project?project=".$GRprojectID;
        $description .= chr(13).chr(13).chr(13);
       
        $description .= "Entity reconciliation should be regarded as semi-automated.";
        $description .= " The quality of the results may vary and the results typically require review and editing in Google Refine. ";
       
        $description .= chr(13).chr(13).chr(13);
        $description .= "Summary tracking information for this dataset is at: ".$summaryLink;
        
        $defaultNote = "[Issue automatically reported by the Data Refine Plugin]";
        
        $t_bug_data = new BugData;
	$t_bug_data->category_id = 1;
	$t_bug_data->severity	= 60;
	$t_bug_data->priority	= 60;			
	$t_bug_data->summary	= $summary;
	$t_bug_data->description = $description;
	$t_bug_data->additional_information = $defaultNote;
        $t_bug_data->project_id = $tableMetadata["issueProjectID"];
        $t_bug_data->reporter_id = $this->issueUserID;
        $t_bug_data->profile_id	 = $this->fallBack_issueProfile_id;

        $t_bug_id = $t_bug_data->create();
        
        $this->finalReconIssue = $t_bug_id;
        
        $newIssue = array("id" => $t_bug_id , "resolved" => false);
        $issues = $tableMetadata["issueIDs"];
        $issues["others"][$t_bug_id] = $newIssue;
        $tableMetadata["issueIDs"] = $issues;
        
        return $tableMetadata;
        
    }



//CANCEL pending processes with the reconciliation service
    public function ReconCancel(){
        
        $message = array(
                         "project" => $this->GRprojectID
                         );
        return $message;
        
    }//end function

    

    //get reconciliation service settings
    public function getSettings($settingKey){
        $settings = $this->settings;
        if(array_key_exists($settingKey, $settings)){
            return $settings[$settingKey];
        }
        else{
            return false;
        }
        
    }

}//end class

?>